package vooga.geom;

import java.awt.geom.Point2D;


/**
 * This class represents a vector (direction and magnitude) within some space.
 * 
 * @author Robert C. Duvall
 * @author Congyi Wu
 * @author Ben Shelton
 */
public class Vector implements Cloneable
{
    private double myDirection;
    private double myMagnitude;

    public final static double LEFT = 180;
    public final static double RIGHT = 0;
    public final static double UP = -90;
    public final static double DOWN = -270;    
    
    public Vector ()
    {
        this(0.0, 1.0);
    }

    /**
     * 
     * @param direction direction in degrees
     * @param magnitude megnitude
     */
    public Vector (double direction, double magnitude)
    {
        setDirection(direction);
        setMagnitude(magnitude);
    }

    public Vector (Point2D source, Point2D target)
    {
        setXYChange(target.getX() - source.getX(),
                    target.getY() - source.getY());
    }

    public Vector (Vector other)
    {
        this(other.getDirection(), other.getMagnitude());
    }
    
    public Vector clone()
    {
    	return new Vector(this);
    }

    public double getMagnitude ()
    {
        return myMagnitude;
    }

    /**
     * 
     * @return direction in degrees
     */
    public double getDirection ()
    {
        return myDirection;
    }

    public double getXChange ()
    {
        return getMagnitude() * Math.cos(Math.toRadians(getDirection()));
    }
    
    public double getYChange ()
    {
        return getMagnitude() * Math.sin(Math.toRadians(getDirection()));
    }


    public Point2D.Double getNextPosition (Point2D.Double current)
    {
        return new Point2D.Double(current.getX() + getXChange(),
                                       current.getY() - getYChange());
    }

    public Vector add (Vector other)
    {
        // BUGBUG: is there an easier way?
        Vector result = new Vector();
        result.setXYChange(getXChange() + other.getXChange(),
                           getYChange() + other.getYChange());
        return result;
    }

    public Vector difference (Vector other)
    {
        // BUGBUG: is there an easier way?
        Vector result = new Vector();
        result.setXYChange(getXChange() - other.getXChange(),
                           getYChange() - other.getYChange());
        return result;
    }

    public Vector negate ()
    {
        return new Vector(-getDirection(), getMagnitude());
    }

    //BAD!!! COMPARING DOUBLES LIKE THIS IS A BAD IDEA
    public boolean equals (Vector other)
    {
        if (this == other)       return true;
        else if (other == null)  return false;
        else
        {
            return (getDirection() == other.getDirection()) &&
                   (getMagnitude() == other.getMagnitude());
        }
    }
    
    public void setMagnitude (double magnitude) 
    {
        myMagnitude = magnitude;
    }

    public void addMagnitude (double change) 
    {
        setMagnitude(getMagnitude() + change);
    }

    /**
     * 
     * @param direction direction in degrees
     */
    public void setDirection (double direction) 
    {
        myDirection = direction % 360;
    }
    
    /**
     * 
     * @param degrees num degrees to turn in counterclockwise direction
     */
    public void turn (double degrees) 
    {
        setDirection(getDirection() + degrees);
    }

    public void setXYChange (double dx, double dy) 
    {
        setDirection(Math.toDegrees(Math.atan2(dy, dx)));
        setMagnitude(Math.sqrt(dx * dx + dy * dy));
    }
    
    public void setXChange(double xMag) {
    	setXYChange (xMag, this.getYChange());
    }
    
    public void setYChange(double yMag) {
    	setXYChange (this.getXChange(), yMag);
    }

    public void flipX() {
    	setXChange(-getXChange());
    }
    
    public void flipY() {
    	setYChange (-getYChange());
    }

    public String toString ()
    {
        return getClass().getName() + 
               "[dir=" + getDirection() + ",mag=" + getMagnitude() + "]";
    }
}
